package jogs;

import jogs.games.Game;

import java.lang.Thread;
import java.net.*;
import java.io.*;
import java.util.logging.Logger;
import java.util.logging.Level;


public class Player extends Thread implements Serializable
{
	private static final long serialVersionUID = 2L;  /** The version of the serialized form of this class. */
	private static final Logger logger = Logger.getLogger(Player.class.getName());  /** The {@link Logger} for this class. */
	static
    {
    	logger.addHandler(GameServer.handler);
    }
	private Socket sock;
	private String playerName;
	private PrintWriter out;
	private BufferedReader in;
	private Game game;
	private GameServer parent;
	private boolean on;
	
	public Player(Socket s, GameServer p)
	{
		sock = s;
		parent = p;
		//game = parent.getGame();
		try
		{
			out = new PrintWriter(sock.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
		}
		catch(Exception e)
		{
			//System.out.println(e);
			logger.log(Level.WARNING, "Problem opening streams\n" + e.toString());
		}
		
	}
	
	public Player(Socket s, GameServer p, String n)
	{
		sock = s;
		playerName = n;
		parent = p;
		//game = p.getGame();
	}
	
	
	
	//Getters 
	//============================================================
	public Socket getSocket()
	{
		return sock;
	}
	
	public String getPlayerName()
	{
		return playerName;
	}
	
	public Game getGame()
	{
		return game;
	}
	
	//Setters
	//==============================================================
	public void setSocket(Socket s)
	{
		sock = s;
	}
	
	public void setPlayerName(String n)
	{
		if(n == null || n == "")
		{
			sendMessage("@ERROR:No Name Was Given");
			return;
		}
		playerName = n;
		this.setName(n);
	}
	
	public void setGame(Game g)
	{
		game = g;
	}
	
	//Other Methods
	//===============================================================
	public void run()
	{
		try
		{
			String input;
			on = true;
			//BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
			while(on && sock.isConnected())
			{
				input = in.readLine();
				if(input != null)
				{
					processInput(input);
				}
			}
			//in.close();
			//this.close();
		}
		catch(Exception e)
		{
			on = false;
			//System.out.println(e);
			logger.log(Level.WARNING, "Problem with connection\n" + e.toString());
			e.printStackTrace();
		}
		Game g = getGame();
		if(g != null)
			parent.leaveGame(g.getName(), this);
		on = false;
		this.setGame(null);
		this.close();	
	}
	
	public boolean sendMessage(String message)
	{
		boolean r = false;
		try 
		{
			out.println(message);
			r = true;
		}
		catch(Exception e)
		{
			logger.log(Level.WARNING, "Problem sending message\n" + e.toString());
			r = false;
		}
		return r;
	}
	
	public boolean send(String message)
	{
		return sendMessage(message);
	}
	
	private void processInput(String input)
	{
		//logger.log(Level.INFO, "Direct message from {0}", this.getName());
		String details = null;
		String command = null;
		
		
		//all commands start with a @ and end with a : 
		int begin = input.indexOf('@');
		int end = input.indexOf(':');
		
		//if @ and : are not in message than it is not a command
		if(begin == -1 || end == -1)
		{
			this.send("@ERROR:Not a valid command");
			return;
		}
		
		//get the command out of the message
		command = input.substring(begin, end);
		
		//if command has details
		if(input.length() > end+1)
			details = input.substring(end+1);
		
		if(this.playerName == null && !command.equals("@NAME"))
		{
			System.out.println(this.playerName);
			this.send("@ERROR:Please enter name first");
			return;
		}
		
		//process the command
		if(command.equals("@NAME"))
		{
			this.setPlayerName(details);
			parent.addPlayer(this.getPlayerName(), this);
			//game.join(this);
		}
		else if(command.equals("@CHAT"))
		{
			if(game != null)
				game.chat(details, this);
		}
		else if(command.equals("@PCHAT"))
		{
			//To be done soon.
		}
		else if(command.equals("@MOVE")) 
		{
			Game g = getGame();
			if(g == null || details == null)
			{
				this.send("@ERROR:Not in a Game now");
				return;
			}
			g.move(this, details);
		}
		else if(command.equals("@JOIN"))
		{
			if(game != null)
			{
				this.send("@ERROR:already in game");
				return;
			}
			Game g = parent.getGame(details);
			if(g == null)
			{
				this.send("@ERROR:there is no game by the name of " + details);
				return;
			}
			parent.joinGame(g.getName(), this);
			game = g;
		}
		else if(command.equals("@CREATE"))
		{
			///Do This.
			if(game != null)
			{
				this.send("@ERROR:already in game");
				return;
			}
			String[] arg = details.split(",");
			String tableName = Game.getNextGameName();
			Game g = parent.createGame(arg[0], tableName, Integer.parseInt(arg[1]), this);
			if(g == null)
			{
				this.send("@ERROR:problem creating game");
				return;
			}
			parent.joinGame(g.getName(), this);
			setGame(g);
			
		}
		else if(command.equals("@LEAVE"))
		{
			Game g = getGame();
			if(g == null)
			{
				this.send("@ERROR:Not in a Game now");
				return;
			}
			parent.leaveGame(g.getName(), this);
			this.setGame(null);
		}
		else if(command.equals("@DISC"))
		{	
			Game g = getGame();
			if(g != null)
				parent.leaveGame(g.getName(),this);
			on = false;
			this.setGame(null);
			this.close();			
		}
		else
		{
			this.send("@ERROR:Not Valid Account");
		}
	}
	
	public void close()
	{
		try
		{
			in.close();
			out.close();
			sock.close();
		}
		catch(Exception e)
		{	
			logger.log(Level.WARNING, "Problem Closing player\n" + e.toString());
		}
	}

	@Override
	public String toString()
	{
		return this.playerName;
	}
	
	public boolean equals(Object obj)
	{
		boolean r = false;
		Player player = (Player)obj;
		if(this.getPlayerName() == player.getPlayerName())
			r = true;
		return r;
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
